#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <paths.h>
#include <openssl/sha.h>
#include <ctype.h>
#include <sys/utsname.h>

#include "kylin-verify.h"
#include "encrypt.h"
#include "dict.h"
#include "date.h"
#include "misc.h"
#include "hwid.h"
#include "kylin-activation.h"

#define BATCH_SERIAL_LEN 7

#ifdef LOG_FILE
#undef LOG_FILE
#endif

#define LOG_FILE "/var/log/kylin-activation-check"

extern void log_write(const char* log_file, const char* message, const char* type);

#define RESULT_INTERFACE "/sys/kylin_authentication/result"
#define BUF_SIZE 1024

static int should_escape = 0;

static GKeyFile* key_file_license = NULL;
static GKeyFile* key_file_kyinfo = NULL;
static char* license_file = "/etc/LICENSE";
static char* license_serial = NULL;
static char* license_to = NULL;
static char* license_method = NULL;
static char* license_term = NULL;
static char* custom_info = NULL;
static unsigned long custom_info_size = 0;
static char* info_file = "/etc/.kyinfo";
static char* escape_expire_date = "2099-12-31";

static int contact_file_stat(const char* name, mode_t mode)
{
	return file_stat(name, mode);
}

static char* contact_file_read(const char* name)
{
	int fd;
	char* result = NULL;
	char buf[BUF_SIZE];
	int ret;

	memset(buf, 0, BUF_SIZE);

	fd = open(name, O_RDONLY);

	if(fd < 0)
		return NULL;

	ret = read(fd, buf, BUF_SIZE);

	if(ret < 0)
	{
		close(fd);
		return NULL;
	}


	result = (char*)malloc(ret + 1);
	if(!result)
	{
		close(fd);
		return NULL;
	}

	result[ret] = '\0';

	memcpy(result, buf, ret);
	close(fd);

	return result;
}


static void contact_file_write(const char* name, const char* data, size_t length)
{
	int fd;
	int ret;

	fd = open(name, O_WRONLY);

	if(fd < 0)
		return;

	ret = write(fd, data, length);
	(void) ret;

	close(fd);
}

static char* digest_generate(const char* whole)
{
	unsigned char md[SHA_DIGEST_LENGTH];
	char buf_str[2 * SHA_DIGEST_LENGTH];
	char* digest = NULL;

	int i;

	SHA_CTX ctx;

	SHA1_Init(&ctx);
	SHA1_Update(&ctx, whole, strlen(whole));
	SHA1_Final(md, &ctx);

	for(i = 0; i < SHA_DIGEST_LENGTH; ++i)
		sprintf(&buf_str[2 * i], "%02x", md[i] & 0xff);

	digest = (char*)malloc(2 * SHA_DIGEST_LENGTH + 1);
	if(!digest)
		return NULL;

	digest[2 * SHA_DIGEST_LENGTH] = '\0';

	memcpy(digest, buf_str, 2 * SHA_DIGEST_LENGTH);

	return digest;
}

static void contact_file_process(const char* file_name, const char* rand_str)
{
	char* whole_str = NULL;
	char* digest = NULL;

	whole_str = g_strconcat(rand_str, "kylin", NULL);
	if(!whole_str)
		return;

	digest = digest_generate(whole_str);

	g_free(whole_str);

	if(!digest || (strlen(digest) != 2 * SHA_DIGEST_LENGTH))
		goto out;
	if(contact_file_stat(file_name, S_IWUSR))
		contact_file_write(file_name, digest, strlen(digest));

out:
	if(digest)
		free(digest);
	return;
}

static void activation_contact(const char* read_file, const char* write_file)
{
	char* rand_str = NULL;

	if(contact_file_stat(read_file, S_IRUSR))
		rand_str = contact_file_read(read_file);

	if((NULL != rand_str) && (strlen(rand_str) == 4))
	{
		contact_file_process(write_file, rand_str);
		free(rand_str);
		rand_str = NULL;
	}

	if (rand_str) {
		free(rand_str);
		rand_str = NULL;
	}
}

static void verify_contact()
{
	char* read_file = NULL;
	char* write_file = NULL;

	read_file = g_strconcat("/", "sys", "/", "kylin", "_", "authentication", "/", "ret", NULL);
	write_file = g_strconcat("/", "sys", "/", "kylin", "_", "authentication", "/", "result", NULL);

	activation_contact(read_file, write_file);
	activation_contact(read_file, read_file);

	// for the old kernel
	if(0 != access(RESULT_INTERFACE, F_OK))
		activation_contact(read_file, read_file);

	if(read_file)
		g_free(read_file);
	if(write_file)
		g_free(write_file);
}

static void env_contact()
{
	char* communicate_file = NULL;

	communicate_file = g_strconcat("/", "sys", "/", "kylin", "_", "authentication", "/", "ret", NULL);

	activation_contact(communicate_file, communicate_file);

	if(communicate_file)
		g_free(communicate_file);
}

#if 0
static char* escape_license_serial_list[] = {
	"dumb-one",
};

static int serial_must_escape(const char* serial)
{
	int i = 0;
	int len = 0;

	if(serial == NULL || strlen(serial) == 0)
		return 0;

	len = strlen(serial);

	if(len == BATCH_SERIAL_LEN)
		return 0;

	for(i = 0; i < len; i++)
	{
		if(!isdigit(serial[i]))
			return 0;
	}

	if(serial[0] == '0')
		return 1;

	return 0;
}

static int is_serial_in_list(const char* serial)
{
	int i = 0;
	for (i = 0; i < sizeof(escape_license_serial_list) / sizeof(char*); i++)
	{
		if (strcmp(serial, escape_license_serial_list[i]) == 0)
			return 1;
	}

	return 0;
}
#endif

static int activation_method_is_place(const char* method)
{
	if(NULL == method)
		return 0;

	if(strcmp(method, "place") == 0)
		return 1;

	return 0;
}

static void set_escape_kyinfo()
{
	if(!key_file_kyinfo || !info_file)
		return;

	if (license_serial)
	{
        	key_file_set_value(key_file_kyinfo, "servicekey", "key", license_serial);
	}

	if (license_to)
	{
		key_file_set_value(key_file_kyinfo, "os", "to", license_to);
	}

	if(license_term)
		key_file_set_value(key_file_kyinfo, "os", "term", license_term);
	key_file_save_to_file(key_file_kyinfo, info_file);
}

int license_should_escape()
{
	int result;
	int ret = 0;
	static unsigned int count = 0;
	char* custom_info = NULL;

	env_contact();
	verify_contact();

	if(!key_file_kyinfo)
        key_file_kyinfo = key_file_load_from_file(info_file);

	if (should_escape)
	{
		set_escape_kyinfo();
		if((count++ % 20) == 0)
		{
			log_write(LOG_FILE, "系统已经激活", "II");
		}
		return 1;
	}

	result = gpg_verify(license_file, &custom_info, &custom_info_size);
	if (result != NO_ERROR)
		goto out;

	if (!key_file_license)
		key_file_license = license_convert_to_keyfile(custom_info, custom_info_size, ':', '=');
	if(!key_file_license)
		goto out;

	if(!license_serial)
		license_serial = key_file_get_value(key_file_license, LICENSE_GROUP, "SERIAL");
	if(!license_serial || strcmp(license_serial, "None") == 0)
	{
		g_key_file_free(key_file_license);
		key_file_license = NULL;
		goto out;
	}
	if(!license_to)
		license_to = key_file_get_value(key_file_license, LICENSE_GROUP, "TO");
	if(license_to)
	{
		if(strcmp(license_to, "None") == 0)
		{
			license_to = NULL;
		}
	}
	if(!license_method)
		license_method = key_file_get_value(key_file_license, LICENSE_GROUP, "METHOD");
	if(license_method)
	{
		if(strcmp(license_method, "None") == 0)
		{
			license_method = NULL;
		}
	}

	if (!license_term)
		license_term = key_file_get_value(key_file_license, LICENSE_GROUP, "TERM");
	if (license_term)
	{
		if (strcmp(license_term, "None") == 0)
		{
			license_term = NULL;
		}
	}

	if(activation_method_is_place(license_method))
	{
		should_escape = 1;
		set_escape_kyinfo();
		log_write(LOG_FILE, "系统已经激活", "II");
		ret = 1;
	}

out:
	if(custom_info) {
		free(custom_info);
		custom_info = NULL;
	}

	return ret;
}


char* escape_get_expire_date()
{
	//获取.kyinfo中的期限
	if(!key_file_kyinfo || !info_file)
		return NULL;

	char* kyinfo_term = key_file_get_value(key_file_kyinfo, "os", "term");
	return kyinfo_term;
	// return escape_expire_date;
}

char* escape_license_serial()
{
	license_should_escape();
	return license_serial;
}

